package org.zjvis.datascience.web.controller;

import cn.weiguangfu.swagger2.plus.annotation.ApiGroup;
import cn.weiguangfu.swagger2.plus.annotation.ApiPlus;
import cn.weiguangfu.swagger2.plus.enums.ApiExecutionEnum;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.api.client.repackaged.com.google.common.base.Joiner;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import javax.validation.Valid;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.zjvis.datascience.common.constant.Constant;
import org.zjvis.datascience.common.constant.UserConstant;
import org.zjvis.datascience.common.dto.sms.SmsDTO;
import org.zjvis.datascience.common.dto.user.UserConfigDTO;
import org.zjvis.datascience.common.dto.user.UserDTO;
import org.zjvis.datascience.common.dto.user.UserFeedbackDTO;
import org.zjvis.datascience.common.enums.NoticeReceiveLevelEnum;
import org.zjvis.datascience.common.exception.BaseErrorCode;
import org.zjvis.datascience.common.exception.DataScienceException;
import org.zjvis.datascience.common.model.ApiResult;
import org.zjvis.datascience.common.model.ApiResultCode;
import org.zjvis.datascience.common.util.DozerUtil;
import org.zjvis.datascience.common.util.FileUtil;
import org.zjvis.datascience.common.util.ImageToMD5Util;
import org.zjvis.datascience.common.util.JwtUtil;
import org.zjvis.datascience.common.vo.user.*;
import org.zjvis.datascience.service.SmsService;
import org.zjvis.datascience.service.UserConfigService;
import org.zjvis.datascience.service.UserService;

/**
 * @description 用户接口 Controller
 * @date 2021-11-24
 */
@ApiPlus(value = true)
@RestController
@RequestMapping("/users")
@Api(tags = "user", description = "用户接口")
@Validated
public class UserController {

    @Autowired
    private UserService userService;
    @Autowired
    private SmsService smsService;
    @Autowired
    private UserConfigService userConfigService;

    private static final int MAX_IMAGE_SIZE = 2000000;
    private static final int MAX_IMAGE_WIDTH = 160;
    private static final int MAX_IMAGE_HEIGHT = 160;

    @ApiGroup(groups = UserVO.Id.class, requestExecution = ApiExecutionEnum.INCLUDE)
    @ApiOperation(value = "根据用户id查询用户信息")
    @PostMapping(value = "/queryById")
    public ApiResult<UserVO> queryById(@Validated(value = UserVO.Id.class) @RequestBody UserVO userVo) {
        UserDTO user = userService.queryById(userVo.getId());
        return ApiResult.valueOf(DozerUtil.mapper(user, UserVO.class));
    }

    @ApiGroup(groups = UserVO.Name.class, requestExecution = ApiExecutionEnum.INCLUDE)
    @PostMapping(value = "/queryByName")
    @ApiOperation(value = "根据用户名查询用户信息")
    public ApiResult<List<UserVO>> queryByName(@RequestBody UserVO userVo) {
        if (StringUtils.isEmpty(userVo.getName())) {
            throw new DataScienceException(UserVO.NAME_BLANK);
        }
        if (userVo.getName().length() < 2) {
            throw new DataScienceException(UserVO.NAME_TOO_SHORT);
        }
        List<UserDTO> users = userService.queryBlurryByName(userVo.getName());
        return ApiResult.valueOf(DozerUtil.mapper(users, UserVO.class));
    }

    /**
     * 先禁用，删除用户是否把所有关联资源删除
     */
//    @PostMapping(value = "/delete")
    public ApiResult<Boolean> deleteById(@Validated(value = UserVO.Id.class) @RequestBody UserVO userVo) {
        return ApiResult.valueOf(userService.delete(userVo.getId()));
    }

    @PostMapping(value = "/create")
    @ApiOperation(value = "用户注册", notes = "新增用户")
    public ApiResult<Long> create(@RequestBody CreateUserVO userVo, @Param(value = "code") String code) {
        if(userVo != null) {
            smsService.verifyMsgCode(userVo.getPhone(), code, UserConstant.TYPE_OF_REGISTER);
            UserDTO user = DozerUtil.mapper(userVo, UserDTO.class);
            return ApiResult.valueOf(userService.save(user));
        } else {
            throw new DataScienceException(BaseErrorCode.USER_INFO_IS_NULL);
        }
    }


    @PostMapping(value = "/update")
    @ApiOperation(value = "用户更新信息", notes = "用户补全信息")
    public ApiResult<Boolean> update(@Valid @RequestParam(value="picture",required = false) MultipartFile picture,
                                     UpdateUserVO userVo) throws Exception {
        UserDTO user = DozerUtil.mapper(userVo, UserDTO.class);
        if (picture != null){
            InputStream in = picture.getInputStream();
            String fileName = picture.getOriginalFilename();
            String lowerCaseName = fileName != null ? fileName.toLowerCase() : "";
            InputStream is = new BufferedInputStream(picture.getInputStream());
            BufferedImage img = ImageIO.read(is);
            int width = img.getWidth();
            int height = img.getHeight();
            if (width > MAX_IMAGE_WIDTH || height > MAX_IMAGE_HEIGHT){
                return ApiResult.valueOf(ApiResultCode.IMAGE_RESOLUTION_ERROR);
            }
            if (!lowerCaseName.endsWith(".jpg") && !lowerCaseName.endsWith(".png") && !lowerCaseName.endsWith(".bmp") && !lowerCaseName.endsWith(".jpeg")) {
                return ApiResult.valueOf(ApiResultCode.IMAGE_FORMAT_ERROR);
            }
            if (picture.getSize() > MAX_IMAGE_SIZE) {
                return ApiResult.valueOf(ApiResultCode.IMAGE_SIZE_ERROR);
            }
            if (picture.getSize() == 0) {
                return ApiResult.valueOf(ApiResultCode.CONTENT_ERROR);
            }
            user.setPicEncode(Constant.PIPELINE_SNAPSHOT_PICTURE_PREFIX+FileUtil.inputStream2Base64(in));
        }else{
            user.setPicEncode(null);
        }
        return ApiResult.valueOf(userService.update(user));
    }

    @PostMapping(value = "/psdModify")
    @ApiOperation(value = "修改密码")
    public ApiResult<Boolean> passwordModify(@Valid @RequestBody UserModifyPasswordVO userVo) {
        String phone = userVo.getPhone();
        SmsDTO value = smsService.getValue(phone, UserConstant.TYPE_OF_MODIFY);
        userService.isEqual(userVo);
        if(value != null && value.isVerified()) {
            userService.updatePassword(userVo);
            return ApiResult.valueOf(true);
        }
        else throw new DataScienceException(BaseErrorCode.USER_PHONE_NOT_VERIFIED);
    }

    /**
     * 反馈页，用户最多上传4张图片
     */
    @PostMapping(value = "/saveFeedback")
    @ApiOperation(value = "用户反馈", notes = "用户反馈")
    public ApiResult<Boolean> saveFeedback(@Valid@RequestParam(value = "picture",required = false) MultipartFile[] pictures, UserFeedbackVO userVo) throws Exception {
        //最多上传4张图片
        if (pictures != null) {
            if (pictures.length > 4) {
                return ApiResult.valueOf(ApiResultCode.FEEDBACK_IMAGE_LENGTH_ERROR);
            }
        }
        String feedback = userVo.getFeedback();
        //判断文字反馈长度
        if(feedback != null) {
            if ((feedback.replace(" ","").length() > 300) || (feedback.replace(" ","").length() < 3)) {
                return ApiResult.valueOf(ApiResultCode.FEEDBACK_LENGTH_ERROR);
            }
            //判断文字反馈字符串是否包括中文或者英文
            if (Pattern.compile("[\u4e00-\u9fa5]").matcher(feedback).find() != true && feedback.matches(".*[a-zA-z].*") != true){
                return ApiResult.valueOf(ApiResultCode.FEEDBACK_CONTENT_ERROR);
            }
        }
        //判断用户是否尝试图片和信息都为空的反馈
        if (feedback == null && pictures.length == 0){
            return ApiResult.valueOf(ApiResultCode.EMPTY_FEEDBACK_ERROR);
        }
        //新建MD5codes list判断是否上传相同图片
        List<String> imagesMD5 = new ArrayList<>();
        //新建list存储图片的编码
        List<String> imageCodes = new ArrayList<>();
        UserFeedbackDTO user = DozerUtil.mapper(userVo, UserFeedbackDTO.class);
        for (MultipartFile picture : pictures) {
            if (picture != null){
                String pictureMD5 = ImageToMD5Util.getMd5(picture);
                imagesMD5.add(pictureMD5);
                InputStream in = picture.getInputStream();
                String fileName = picture.getOriginalFilename();
                String lowerCaseName = fileName.toLowerCase();
                if (!lowerCaseName.endsWith(".jpg") && !lowerCaseName.endsWith(".png") && !lowerCaseName.endsWith(".bmp") && !lowerCaseName.endsWith(".jpeg")) {
                    return ApiResult.valueOf(ApiResultCode.IMAGE_FORMAT_ERROR);
                }
                if (picture.getSize() > MAX_IMAGE_SIZE) {
                    return ApiResult.valueOf(ApiResultCode.IMAGE_SIZE_ERROR);
                }
                if (picture.getSize() == 0) {
                    return ApiResult.valueOf(ApiResultCode.CONTENT_ERROR);
                }
                imageCodes.add(Constant.PIPELINE_SNAPSHOT_PICTURE_PREFIX + FileUtil.inputStream2Base64(in));
            }
        }
        //判断是否上传了相同图片
        HashSet<String> hashSet = new HashSet<>(imagesMD5);
        if (imagesMD5.size() != hashSet.size()) {
            return ApiResult.valueOf(ApiResultCode.DUPLICATE_IMAGE_ERROR);
        }
        String picCodes = Joiner.on("|").join(imageCodes);
        user.setFeedbackPic(picCodes);
        return ApiResult.valueOf(userService.insertFeedback(user));
    }

    /**
     * 修改用户引导状态
     */
    @PostMapping(value = "/guideChange")
    @ApiOperation(value = "新用户引导状态", notes = "新用户状态修改")
    public ApiResult<Boolean> guideStatusChange(@RequestBody Long id) {
        return ApiResult.valueOf(userService.changeGuideStatus(id));
    }

    /**
     * 查询用户引导状态
     */
    @PostMapping(value = "/guideCheck")
    @ApiOperation(value = "新用户状态", notes = "新用户状态查询")
    public ApiResult<Integer> guideStatusCheck(@RequestBody Long id) {
        return ApiResult.valueOf(userService.checkGuideStatus(id));
    }

    @ApiGroup(groups = UserConfigVO.Level.class ,requestExecution = ApiExecutionEnum.INCLUDE)
    @PostMapping(value = "/queryUserConfig")
    @ApiOperation(value = "获取用户配置信息", notes = "获取用户配置信息")
    public ApiResult<UserConfigDTO> queryUserConfig() {
        return ApiResult.valueOf(userConfigService.query(JwtUtil.getCurrentUserId()));
    }

    @ApiGroup(groups = UserConfigVO.Level.class ,requestExecution = ApiExecutionEnum.INCLUDE)
    @PostMapping(value = "/updateNoticeReceiveLevel")
    @ApiOperation(value = "更新消息接收级别", notes = "更新消息接收级别")
    public ApiResult<Boolean> updateNoticeReceiveLevel(@Validated(value=UserConfigVO.Level.class) @RequestBody UserConfigVO vo) {
        return ApiResult.valueOf(userConfigService.update(vo));
    }

    @ApiGroup(groups = UserConfigVO.SecondaryConfirmation.class ,requestExecution = ApiExecutionEnum.INCLUDE)
    @PostMapping(value = "/updateNodeDeletionSecondaryConfirmation")
    @ApiOperation(value = "更新删除节点二次确认", notes = "更新删除节点二次确认")
    public ApiResult<Boolean> updateNodeDeletionSecondaryConfirmation(@Validated(value=UserConfigVO.SecondaryConfirmation.class) @RequestBody UserConfigVO vo) {
        return ApiResult.valueOf(userConfigService.update(vo));
    }

    @PostMapping(value = "/queryNoticeReceiveLevel")
    @ApiOperation(value = "获取更新消息接收级别列表", notes = "获取更新消息接收级别列表")
    public ApiResult<Object> queryNoticeReceiveLevel() {
        JSONArray ja = new JSONArray();
        NoticeReceiveLevelEnum[] notices = NoticeReceiveLevelEnum.values();
        for (NoticeReceiveLevelEnum notice:notices) {
            JSONObject jo = new JSONObject();
            jo.put("level",notice.getLevel());
            jo.put("name",notice.getName());
            ja.add(jo);
        }
        return ApiResult.valueOf(ja);
    }

    @PostMapping(value = "/bind")
    @ApiOperation(value = "手机绑定", notes = "手机绑定")
    public ApiResult<Boolean> phoneBind(@RequestBody JSONObject obj) {
        String phone = obj.getString("phone");
        String code = obj.getString("code");
        UserDTO user = JwtUtil.getCurrentUserDTO();
        if(user.getPhone() != null && !user.getPhone().equals("")) {
            SmsDTO value = smsService.getValue(user.getPhone(), UserConstant.TYPE_OF_BIND);
            if (value == null || !value.isVerified()) {
                throw new DataScienceException(BaseErrorCode.USER_PHONE_NOT_VERIFIED);
            }
        }
        if(phone != null) {
            smsService.verifyMsgCode(phone, code, UserConstant.TYPE_OF_BIND);
            return ApiResult.valueOf(userService.phoneBind(user, phone));
        } else {
            throw new DataScienceException(BaseErrorCode.USER_INFO_IS_NULL);
        }
    }

    @PostMapping(value = "/bindChange")
    @ApiOperation(value = "手机改绑", notes = "手机改绑校验,旧手机号验证验证码")
    public ApiResult<Boolean> phoneBindChange(@RequestBody JSONObject obj) {
        UserDTO user = JwtUtil.getCurrentUserDTO();
        String code = obj.getString("code");
        return ApiResult.valueOf(smsService.verifyMsgCode(user.getPhone(), code, UserConstant.TYPE_OF_BIND));
    }
}
